#include <iostream>
#include <unistd.h>
#include <vector>
#include "mythread.hpp"
#include "MyMutex.hpp"
using namespace std;

pthread_cond_t cond_t = PTHREAD_COND_INITIALIZER; //全局的条件变量


class ThreadData //将要传入线程的数据进行封装，这里有一个线程名和一个互斥锁
{
public:
    ThreadData(const std::string &name, pthread_mutex_t *lock)
        : threadname(name), pmutex(lock)
    {}

public:
    std::string threadname;
    pthread_mutex_t *pmutex;
};

// 应用方
string getName()
{
    static int cnt = 1;
    char name[128];
    snprintf(name, sizeof(name), "Thread-%d", cnt++);
    return name;
}

void Print(int data)
{
    while (data--)
    {
        sleep(1);
        cout << "hello world : " << data << endl;
    }
}

int resource = 10000;
// pthread_mutex_t mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP; //定义全局的锁
void apply(ThreadData *td)
{
    while (true)
    {
        {
            //usleep(1000);
            LockGuard lock = LockGuard(td->pmutex); // 用锁构造我们封装的类,锁的加锁和释放随lock的生命周期          
            if (resource > 0)
            {
                cout << td->threadname << ":hello world : " << resource << endl;
                resource--;
            }
            else
            {
                pthread_cond_wait(&cond_t,td->pmutex);  //等待条件变量
            }
        }

        //...
    }
}

int main()
{
    vector<Thread<ThreadData *>> threads;
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, nullptr);

    // pthread_cond_t cond; //条件变量局部初始化
    // pthread_cond_init(&cond, nullptr);

    // pthread_cond_destroy(&cond); //需要手动释放

    string name1 = getName();
    ThreadData *td1 = new ThreadData(name1, &mutex); 

    string name2 = getName();
    ThreadData *td2 = new ThreadData(name2, &mutex);

    string name3 = getName();
    ThreadData *td3 = new ThreadData(name3, &mutex);

    string name4 = getName();
    ThreadData *td4 = new ThreadData(name4, &mutex);

    threads.push_back(Thread<ThreadData *>(name1, apply, td1));
    threads.push_back(Thread<ThreadData *>(name2, apply, td2));
    threads.push_back(Thread<ThreadData *>(name3, apply, td3));
    threads.push_back(Thread<ThreadData *>(name4, apply, td4));

    for (auto &th : threads) // 需要引用，不然会进行拷贝成临时变量，原数组中的线程状态不会改变
    {
        th.Start();
    }

    while(true)
    {
        sleep(6);
        LockGuard lock = LockGuard(&mutex);
        resource += 1000; //每隔6s加票
        pthread_cond_signal(&cond_t);  //唤醒一个线程,使得线程按照一定顺序执行
        pthread_cond_broadcast(&cond_t);  //唤醒全部线程
    }

    for (auto &th : threads) // 如果不是引用，这里的th就是非运行状态，则不会进行阻塞等待，最后进程退出，线程全部释放
    {
        // cout << th.isRunning() << endl;
        th.join();
    }

    pthread_mutex_destroy(&mutex);  //局部的锁要手动释放

    return 0;
}